package com.pitop.base;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.pitop.core.annotation.Ignore;
import com.pitop.core.enums.Gender;
import com.pitop.core.exceptions.BaseException;
import com.pitop.core.tools.redis.RedisKey;
import com.pitop.core.tools.redis.RedisUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lixin on 2017/6/3.
 */
@RestController
@RequestMapping("/res")
@Slf4j
@Api(value = "枚举资源接口", description = "系统中的枚举查询接口通过此控制器可以获得，资源是从类映射到缓存中存放，最后通过接口返回")
public class EnumCtrl {

    @Resource
    public RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RedisUtils redisUtils;


    /**
     * 通用枚举获取接口
     * 1.检查缓存，不存在就缓存
     * 2.缓存中获取
     *
     * @return
     */
    @ApiOperation(value = "通用枚举获取接口", notes = "系统通用枚举自动获取")
    @GetMapping("/enum/error")
    @ResponseBody
    public Map<String, String> errorEnum() {
        Map<String, String> map = Maps.newHashMap();
        for (BaseException.BaseExceptionEnum baseExceptionEnum : BaseException.BaseExceptionEnum.values()) {
            map.put(String.valueOf(baseExceptionEnum.errCode), baseExceptionEnum.error);
        }
        return map;

    }


    /**
     * 通用枚举获取接口
     * 1.检查缓存，不存在就缓存
     * 2.缓存中获取
     *
     * @param code 枚举编码
     * @return
     */
    @ApiOperation(value = "通用枚举获取接口", notes = "系统通用枚举自动获取")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "枚举编码(可调用/res/enum/codes接口查找所需枚举编码)", required = true, paramType = "path")
    })
    @GetMapping("/enum/{code}")
    @ResponseBody
    public Map<String, String> commonEnum(@PathVariable Integer code) {
        Map<String, String> map;
        Assert.notNull(code, BaseException.BaseExceptionEnum.Empty_Param.toString());
        String cachekey = RedisKey.genCachekey(code);

        //1.检查缓存，不存在就缓存
        if (!redisUtils.hasKey(cachekey)) {
            map = Enums.genMap(code);
            redisUtils.set(cachekey, JSON.toJSONString(map));
            log.info("通用枚举获取接口 : " + JSON.toJSONString(map));
            return map;
        } else {
            //2.缓存中获取
            String mapStr = redisUtils.get(cachekey).toString();
            log.info("通用枚举获取接口 : " + mapStr);
            return JSON.parseObject(mapStr, Map.class);
        }

    }

    /**
     * 枚举汇总
     *
     * @return
     */
    @ApiOperation(value = "枚举汇总", notes = "系统通用枚举 汇总查阅")
    @GetMapping("/enum/codes")
    @ResponseBody
    public List<Map<String, String>> getEnumCodes() {
        List<Map<String, String>> list = null;
        String cachekey = RedisKey.genCacheTotlakey();
        try {
            //1.检查缓存，不存在就缓存
            if (!redisUtils.hasKey(cachekey)) {
                list = Enums.getEnumsDescs();
                redisUtils.set(cachekey, JSON.toJSONString(list));
                return list;
            } else {
                //2.缓存中获取
                String mapStr = redisUtils.get(cachekey).toString();
                return JSON.parseObject(mapStr, List.class);
            }
        } catch (Exception e) {
            log.info(e.getMessage());
        }
        return list;
    }

    /**
     * 枚举管理器
     */
    private enum Enums {
        TestUnitState(1000, com.pitop.test.entity.TestUnitState.class)/*测试单元状态*/,
        StaffState(1001, com.pitop.staff.entity.StaffState.class)/*员工状态*/,
        ErrortypeState(1002, com.pitop.errortype.entity.ErrortypeState.class)/*错误类型状态*/,
        TestOptionState(1003, com.pitop.test.entity.TestOptionState.class)/*测试项状态*/,
        TestRecordState(1004, com.pitop.test.entity.TestRecordState.class)/*测试记录状态*/,
        RepairFeedbackState(1005, com.pitop.repair.entity.RepairFeedbackState.class)/*检修状态*/,
        GenderState(1006, Gender.class)/*性别状态*/,
        MarketRepairRecordState(1007, com.pitop.market.entity.MarketRepairRecordState.class)/*维修记录状态*/,
        RepairStaffState(1008, com.pitop.repair.entity.RepairStaffState.class)/*维修账户状态*/,
        MaterialState(1009, com.pitop.material.entity.MaterialState.class)/*供应料材状态*/,
        SupplierState(1010, com.pitop.supplier.entity.SupplierState.class)/*供应商状态*/,
        SupplierCompanyNature(1011, com.pitop.supplier.entity.SupplierCompanyNature.class)/*供应商公司性质*/,
        FrontendI18nCategoryState(1012, com.pitop.frontend.entity.FrontendI18nCategoryState.class)/*前端国际化分类状态*/,
        FrontendI18nState(1013, com.pitop.frontend.entity.FrontendI18nState.class)/*前端国际化状态*/,
        LanguageEnum(1014, com.pitop.core.enums.LanguageEnum.class)/*语言编码*/,
        TestItemsEnum(1015, com.pitop.test.entity.TestItems.class)/*测试项类型枚举*/,
        ErrorCodePoolState(1016, com.pitop.errorcode.entity.ErrorcodePoolState.class)/*错误码库的状态*/,
        MaterialSupplierState(1017, com.pitop.material.entity.MaterialSupplierState.class)/*物料供应商状态*/,
        BoxSyncState(1018, com.pitop.box.entity.BoxSyncState.class)/*箱库存 同步状态*/,
        BoxState(1019, com.pitop.box.entity.BoxState.class)/*箱库存 的实体类的状态*/,
        OrderState(1020, com.pitop.order.entity.OrderStateEnum.class)/*订单 的实体类的状态*/,
        BomState(1022, com.pitop.bom.entity.BomState.class)/*bom状态*/,
        BomLogState(1023, com.pitop.bom.entity.BomLogState.class)/*bom日志事件*/,
        BomDetailState(1024, com.pitop.bom.entity.BomDetailState.class)/*bom明细状态*/,
        BomDetailType(1025, com.pitop.bom.entity.BomDetailType.class)/*bom明细类型*/,
        BomDetailLogState(1026, com.pitop.bom.entity.BomDetailLogState.class)/*bom明细事件类型*/,
        MouldState(1027, com.pitop.mould.entity.MouldState.class)/*模具状态*/,
        ProductState(1028, com.pitop.product.entity.ProductState.class)/*成品状态*/,
        ProjectState(1029, com.pitop.project.entity.ProjectState.class)/*项目状态*/,
        ProjectLogState(1030, com.pitop.project.entity.ProjectLogState.class)/*项目变更日志事件*/,
        MaterialLogState(1031, com.pitop.material.entity.MaterialLogState.class)/*物料日志事件类型*/,
        AssemblyState(1032, com.pitop.assembly.entity.AssemblyState.class)/*组件状态*/,
        AssemblyCategoryState(1033, com.pitop.assembly.entity.AssemblyCategoryState.class)/*组件类型状态*/,
        AssemblyLogState(1034, com.pitop.assembly.entity.AssemblyLogState.class)/*组件日志事件*/,

        /**/;

        public int code;
        public Class clazz;

        Enums(int code, Class clazz) {
            this.code = code;
            this.clazz = clazz;
        }

        public static Enums getEnums(Integer code) {
            for (Enums enums : Enums.values()) {
                if (enums.code == code) {
                    return enums;
                }
            }
            return null;
        }

        /**
         * 反射获取枚举键值关系
         *
         * @param code 枚举编号
         * @return
         * @throws InstantiationException
         */
        public static Map<String, String> genMap(Integer code) {
            try {
                Enums enums = getEnums(code);
                if (enums == null) {
                    return null;
                }
                Class clazz = enums.clazz;

                Map<String, String> map = Maps.newHashMap();
                if (clazz.isEnum()) {
                    Field[] fs = clazz.getDeclaredFields();//获得类的所有属性

                    //收集被忽略集合
                    List<String> ignoreKeys = new ArrayList<>();
                    for (Field field : fs) {
                        Ignore ignore = field.getAnnotation(Ignore.class);//判断是否具备注解
                        if (ignore != null) {
                            ignoreKeys.add(field.getName());//被忽略的属性
                        }
                    }

                    for (Object obj : clazz.getEnumConstants()) {
                        String type = obj.toString();
                        String classType = obj.getClass().getTypeName();
                        classType = classType.substring(classType.lastIndexOf(".") + 1);
                        for (int i = 0; i < fs.length; i++) {
                            Field f = fs[i];
                            f.setAccessible(true);
                            String fType = f.getType().getTypeName();

                            if (!fType.contains(classType)) {
                                Object val = f.get(obj);
                                map.put(type, val == null ? type : val.toString());
                            }
                        }
                    }

                    //忽略键
                    ignoreKeys.forEach(ignoreKey -> map.remove(ignoreKey));
                }
                return map;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }

        public static List<Map<String, String>> getEnumsDescs() {
            List<Map<String, String>> list = new ArrayList<Map<String, String>>();
            for (Enums enums : Enums.values()) {
                Map<String, String> map = new HashMap<>();
                map.put("枚举编码 [code = " + String.valueOf(enums.code) + "]", enums.name());
                list.add(map);
            }
            return list;
        }
    }


}
